Skip to content

Conversation

@Tomo1912
Copy link

@Tomo1912 Tomo1912 commented Jan 5, 2026

Summary

This PR adds Server-Side Request Forgery (SSRF) protection and a comprehensive security test suite to the fetch MCP server.

Security Features Added

SSRF Protection

  • URL scheme validation (only http/https allowed)
  • Private IP range blocking (10.x, 172.16-31.x, 192.168.x, 127.x, etc.)
  • IPv6 private address blocking (::1, fe80::, fc00::, etc.)
  • Dangerous hostname blocking (localhost, metadata services, etc.)
  • DNS resolution validation to prevent DNS rebinding
  • Configurable via MCP_FETCH_ALLOW_PRIVATE_IPS env var
  • Whitelist support via MCP_FETCH_ALLOWED_PRIVATE_HOSTS

SSL Configuration

  • Configurable SSL verification via MCP_FETCH_SSL_VERIFY env var
  • Comprehensive SSL error handling with helpful messages

Test Suite (89 tests)

  • SSRF protection tests
  • Private IP blocking tests
  • Input validation tests
  • URL scheme validation tests
  • Integration tests
  • Edge case tests

Configuration

# Disable SSL verification for self-signed certs
export MCP_FETCH_SSL_VERIFY=false

# Allow private IPs (use with caution)
export MCP_FETCH_ALLOW_PRIVATE_IPS=true

# Whitelist specific internal hosts
export MCP_FETCH_ALLOWED_PRIVATE_HOSTS=internal.company.com,api.local

Server Details

  • Server: fetch
  • Changes to: Security (SSRF protection, SSL config), tests

Motivation and Context

The fetch server can be exploited for SSRF attacks, allowing malicious actors to access internal services (cloud metadata endpoints, internal APIs, etc.). This PR adds comprehensive protection while maintaining flexibility for legitimate internal use cases through configuration options.

How Has This Been Tested?

  • 89 security tests pass locally
  • Tested with pyright (0 errors)
  • CI pipeline passes

Breaking Changes

None. All protections are backward compatible. Private IPs can be enabled via env var if needed.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Protocol Documentation
  • My changes follows MCP security best practices
  • I have updated the server's README accordingly
  • I have tested this with an LLM client
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have documented all environment variables and configuration options

Additional context

This PR builds on #3179 which adds SSL verification configuration.

@Tomo1912 Tomo1912 force-pushed the feat/security-hardening branch 3 times, most recently from d0c9333 to 2892ae1 Compare January 8, 2026 20:53
@Tomo1912 Tomo1912 force-pushed the feat/security-hardening branch from 7e6a302 to 345a570 Compare January 19, 2026 22:19
@Tomo1912 Tomo1912 force-pushed the feat/security-hardening branch from 0e0769e to a4ce0fc Compare January 27, 2026 12:29
@Tomo1912 Tomo1912 force-pushed the feat/security-hardening branch 2 times, most recently from 7703e1e to 2a2c923 Compare February 4, 2026 18:06
This PR adds Server-Side Request Forgery (SSRF) protection and a comprehensive
security test suite to the fetch MCP server.

- URL scheme validation (only http/https allowed)
- Private IP range blocking (10.x, 172.16-31.x, 192.168.x, 127.x, etc.)
- IPv6 private address blocking (::1, fe80::, fc00::, etc.)
- Dangerous hostname blocking (localhost, metadata services, etc.)
- DNS resolution validation to prevent DNS rebinding
- Configurable via MCP_FETCH_ALLOW_PRIVATE_IPS env var
- Whitelist support via MCP_FETCH_ALLOWED_PRIVATE_HOSTS

- Configurable SSL verification via MCP_FETCH_SSL_VERIFY env var
- Comprehensive SSL error handling with helpful messages

- SSRF protection tests
- Private IP blocking tests
- Input validation tests
- URL scheme validation tests
- Integration tests
- Edge case tests

```bash
export MCP_FETCH_SSL_VERIFY=false

export MCP_FETCH_ALLOW_PRIVATE_IPS=true

export MCP_FETCH_ALLOWED_PRIVATE_HOSTS=internal.company.com,api.local
```

fix: address security review feedback

- Disable follow_redirects to prevent SSRF bypass via open redirects
- Add explicit IP obfuscation detection (decimal/octal/hex formats)
- Fix SSL parsing to be fail-secure (only 'false' disables verification)
- Clean up test headers (remove enterprise roleplay language)
- Add comprehensive tests for IP obfuscation parsing

fix: add octal integer IP parsing and fix test naming

- Add octal integer format parsing (017700000001 = 127.0.0.1)
- Rename SSL test to reflect fail-secure behavior (stays_enabled, not defaults_to_false)
- Add tests for octal integer IP obfuscation
@Tomo1912 Tomo1912 force-pushed the feat/security-hardening branch from 2a2c923 to 7aabbb4 Compare February 4, 2026 18:08
@lucamorettibuilds
Copy link

This is an excellent and comprehensive approach to SSRF protection! The layered defense strategy and extensive test coverage show a deep understanding of the security requirements.

What's done really well:

  1. Defense in depth - URL validation → DNS resolution → IP blocking is the correct order of operations
  2. IPv6 coverage - Many SSRF implementations forget link-local (fe80::) and ULA (fc00::) ranges
  3. Cloud metadata protection - Blocking 169.254.169.254 prevents the classic AWS metadata service attack
  4. Escape hatch design - The whitelist approach (MCP_FETCH_ALLOWED_PRIVATE_HOSTS) is much better than a global override
  5. 89 tests - This gives real confidence the edge cases are covered

Security considerations:

⚠️ DNS rebinding timing - The current approach validates the resolved IP before making the request, but there's a TOCTOU (time-of-check-time-of-use) window. An attacker-controlled DNS server could:

  1. Return a public IP during the validation check
  2. Change to a private IP between validation and the actual fetch

Mitigation options:

  • Use a custom DNS resolver that caches the resolved IP and passes it directly to the HTTP client
  • Or: Re-validate the IP immediately before connection (check if Python's requests library allows IP pinning)
  • Or: Document this as a known limitation with the recommendation to use network-level SSRF protection (firewall rules, egress filtering)

🔒 Redirect handling - Does the fetch server follow HTTP redirects? If yes, an attacker could bypass SSRF protection:

https://evil.com/redirect → http://169.254.169.254/latest/meta-data/

Should validate every URL in the redirect chain, or disable redirects entirely.

📋 Private IP bypass with octal/hex encoding - Does the IP parser handle these edge cases?

  • http://0x7f.0.0.1 (127.0.0.1 in hex)
  • http://2130706433 (127.0.0.1 as decimal integer)
  • http://017700000001 (127.0.0.1 in octal)

Python's ipaddress library should handle these, but worth testing.

Recommendation:

This is production-ready for most use cases. For maximum security in high-risk environments, I'd suggest:

  1. Checking redirect handling behavior
  2. Adding a note in the README about the DNS rebinding timing window
  3. Recommending network-level egress controls as defense-in-depth

Really strong work on this — the 89-test suite and comprehensive IP range coverage are exemplary!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants